home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #2 / Ham Radio 2000 - Volume 2.iso / HAMV2 / TCP_IP / TNOS230S / CMDPARSE.C < prev    next >
Encoding:
C/C++ Source or Header  |  1997-08-18  |  13.0 KB  |  586 lines

  1. /* Parse command line, set up command arguments Unix-style, and call function.
  2.  * Note: argument is modified (delimiters are overwritten with nulls)
  3.  *
  4.  * Copyright 1991 Phil Karn, KA9Q
  5.  *
  6.  * Improved error handling by Brian Boesch of Stanford University
  7.  * Feb '91 - Bill Simpson
  8.  *        bit16cmd for PPP
  9.  * Mar '91 - Glenn McGregor
  10.  *        handle string escaped sequences
  11.  */
  12. #ifdef MSDOS
  13. #include <conio.h>
  14. #endif
  15. #include "global.h"
  16. #include "ctype.h"
  17. #include "proc.h"
  18. #include "commands.h"
  19. #include "session.h"
  20. #include "pktdrvr.h"
  21.  
  22. #if !defined(_lint)
  23. static char rcsid[] OPTIONAL = "$Id: cmdparse.c,v 1.15 1997/08/19 01:19:22 root Exp root $";
  24. #endif
  25.  
  26. #ifdef LOCK
  27. int Kblocked;
  28. char *Kbpasswd;
  29. #endif
  30.  
  31. extern long btol (char *s);
  32.  
  33. int cmdparse_newproc_type = PTYPE_NORMAL;
  34.  
  35. static void redir_cleanup (void);
  36.  
  37.  
  38. struct boolcmd {
  39.     const char *str;    /* Token */
  40.     int val;        /* Value */
  41. };
  42.  
  43.  
  44. static struct boolcmd Boolcmds[] =
  45. {
  46.     {"y", 1},        /* Synonyms for "true" */
  47.     {"yes", 1},
  48.     {"true", 1},
  49.     {"on", 1},
  50.     {"1", 1},
  51.     {"set", 1},
  52.     {"enable", 1},
  53.  
  54.     {"n", 0},        /* Synonyms for "false" */
  55.     {"no", 0},
  56.     {"false", 0},
  57.     {"off", 0},
  58.     {"0", 0},
  59.     {"clear", 0},
  60.     {"disable", 0},
  61.     {NULLCHAR, 0}
  62. };
  63.  
  64. static char *stringparse (char *line, int braced);
  65.  
  66.  
  67. static char *
  68. stringparse (line, braced)
  69. char *line;
  70. int braced;
  71. {
  72. register char *cp = line;
  73. unsigned long num;
  74. char check = (braced) ? '}' : '\"';
  75.  
  76.     while (*line != '\0' && *line != check) {
  77.         if (*line == '\\') {
  78.             line++;
  79.             switch (*line++) {
  80.                 case 'n':    *cp++ = '\n';
  81.                         break;
  82.                 case 't':    *cp++ = '\t';
  83.                         break;
  84.                 case 'v':    *cp++ = '\v';
  85.                         break;
  86.                 case 'b':    *cp++ = '\b';
  87.                         break;
  88.                 case 'r':    *cp++ = '\r';
  89.                         break;
  90.                 case 'f':    *cp++ = '\f';
  91.                         break;
  92. #ifdef TNOS_68K
  93.                 case 'l':    *cp++ = '\l';
  94.                         break;
  95. #endif
  96.                 case 'a':    *cp++ = '\007';
  97.                         break;
  98.                 case '\\':    *cp++ = '\\';
  99.                         break;
  100.                 case '\?':    *cp++ = '\?';
  101.                         break;
  102.                 case '\'':    *cp++ = '\'';
  103.                         break;
  104.                 case ';':    *cp++ = ';';
  105.                         break;
  106.                 case '{':    *cp++ = '{';
  107.                         break;
  108.                 case '}':    *cp++ = '}';
  109.                         break;
  110.                 case '>':    *cp++ = '>';
  111.                         break;
  112.                 case '\"':    *cp++ = '\"';
  113.                         break;
  114.                 case 'x':    num = strtoul (--line, &line, 16);
  115.                         *cp++ = (char) num;
  116.                         break;
  117.                 case '0':
  118.                 case '1':
  119.                 case '2':
  120.                 case '3':
  121.                 case '4':
  122.                 case '5':
  123.                 case '6':
  124.                 case '7':    num = strtoul (--line, &line, 8);
  125.                         *cp++ = (char) num;
  126.                         break;
  127.                 case '\0':    return NULLCHAR;
  128.                 default:    *cp++ = *(line - 1);
  129.                         break;
  130.             }
  131.         } else
  132.             *cp++ = *line++;
  133.     }
  134.  
  135.     if (*line == check)
  136.         line++;        /* skip final quote */
  137.     *cp = '\0';        /* terminate string */
  138.     return line;
  139. }
  140.  
  141.  
  142.  
  143. static void
  144. redir_cleanup (void)
  145. {
  146.     if (Curproc == Command->proc && Command->rfile != NULLCHAR)    {
  147.         rflush ();
  148.         kwait (NULL);
  149.         Command->rfile = NULLCHAR;
  150.         fputc ('\n', Command->record);
  151.         (void) fclose (Command->record);
  152.         Command->record = NULLFILE;
  153.     }
  154. }
  155.  
  156.  
  157.  
  158. int
  159. cmdparse (cmds, line, p)
  160. struct cmds cmds[];
  161. register char *line;
  162. void *p;
  163. {
  164. struct cmds *cmdp;
  165. char const *argv[NARG];
  166. char *cp, c;
  167. char **pargv;
  168. int argc, i, isconv;
  169. char *nextline;
  170. int inbrace, indquote, done;
  171.  
  172. int check4redir = 0;
  173. char *doredir;
  174. int inAcommentline;
  175.  
  176.     /* Remove cr/lf */
  177.     rip (line);
  178.  
  179.     if (Curproc == Command->proc)
  180.         check4redir = 1;
  181.  
  182. loop:            /* this section handles multi-command lines, using a ';' */
  183.     redir_cleanup ();
  184.     nextline = NULLCHAR;
  185.     doredir = NULLCHAR;
  186.     inAcommentline = 0;
  187.     line = skipwhite (line);
  188.     done = inbrace = indquote = 0;
  189.     for (cp = line; *cp && !done; cp++) {
  190.         switch (*cp) {
  191.             case '#':    if (cp == line)
  192.                         inAcommentline = 1;
  193.                     break;
  194.             case '{':    if (!indquote && !inAcommentline)
  195.                         inbrace += 1;
  196.                     break;
  197.             case '}':    if (!indquote && !inAcommentline)
  198.                         inbrace -= 1;
  199.                     break;
  200.             case '\"':    if (!inbrace && !inAcommentline)
  201.                         indquote ^= 1;
  202.                     break;
  203.             case '\\':    if (!inAcommentline)    {
  204.                         c = *(cp + 1);
  205.                         if (c == '{' || c == '}' || c == '\"' || c == ';' || (check4redir && c == '>'))
  206.                             cp++;
  207.                     }
  208.                     break;
  209.             case ';':    if (!inbrace && !indquote && !inAcommentline) {
  210.                         *cp++ = 0;
  211.                         nextline = cp;
  212.                         done = 1;
  213.                     }
  214.                     break;
  215.             case '>':    if (check4redir && !inAcommentline)    {
  216.                         *cp++ = 0;
  217.                         doredir = cp;
  218.                     }
  219.                     break;
  220.             default:    break;
  221.         }
  222.     }
  223.  
  224.     for (argc = 0; argc < NARG; argc++)
  225.         argv[argc] = NULLCHAR;
  226.  
  227.     if (check4redir && doredir != NULLCHAR)    {
  228.         /* output redirection found */
  229.         Command->rfile = skipwhite (doredir);
  230.         Command->record = fopen (Command->rfile, APPEND_TEXT);
  231.         if (Command->record == NULLFILE)    {
  232.             tprintf ("Can't open %s: %s\n", Command->rfile, SYS_ERRLIST(errno));
  233.             Command->rfile = NULLCHAR;
  234.         }
  235.     }
  236.     for (argc = 0; argc < NARG;) {
  237.         register int qflag = FALSE;
  238.         register int qflag2 = FALSE;
  239.  
  240.         /* Skip leading white space */
  241.         while (*line == ' ' || *line == '\t')
  242.             line++;
  243.         if (*line == '\0')
  244.             break;
  245.         /* return if comment character first non-white */
  246.         if (argc == 0 && *line == '#')
  247.             goto multichk;
  248.         /* Check for quoted token */
  249.         if (*line == '"' && strchr (line + 1, '"')) {
  250.             line++;    /* Suppress quote */
  251.             qflag = TRUE;
  252.         } else if (*line == '{' && strchr (line + 1, '}')) {    /* Check for braced token */
  253.             line++;    /* Suppress quote */
  254.             qflag2 = TRUE;
  255.         }
  256.         argv[argc++] = line;    /* Beginning of token */
  257.  
  258.         if (qflag || qflag2) {    /* Find terminating delimiter */
  259.             if ((line = stringparse (line, qflag2)) == NULLCHAR)
  260.                 goto errret;
  261.         } else {
  262.             /* Find space or tab. If not present,
  263.              * then we've already found the last
  264.              * token.
  265.              */
  266.             if ((cp = strpbrk (line, " \t")) == NULLCHAR)
  267.                 break;
  268.             *cp++ = '\0';
  269.             line = cp;
  270.         }
  271.     }
  272.     if (argc < 1) {        /* empty command line */
  273.         argc = 1;
  274.         argv[0] = "";
  275.     }
  276. #ifdef LOCK
  277.     /* Check to see if this is the Command session.
  278.      * If so, check to see if the keyboard is locked
  279.      * Added 12/12/91 WG7J
  280.      * Also, skips this check if it is a command from the AT queue 12/16/93 KO4KS
  281.      */
  282.     if ((Curproc->input == Command->input) && strcmp ("AT handler", Curproc->name))
  283.         if (Kblocked) {    /*check argv[0] for password!*/
  284.             if (stricmp (argv[0], Kbpasswd)) {
  285.                 tputs ("\nKeyboard remains locked\n");
  286.                 return 0;
  287.             }
  288.             Command->ttystate.echo = 1;    /* turn character echo back on ! */
  289.             Kblocked = 0;    /* correct password, so unlock */
  290.             tputc ('\n');
  291.             redir_cleanup ();
  292.             return 0;
  293.         }
  294. #endif
  295.  
  296.     /* Look up command in table; prefix matches are OK */
  297.     for (cmdp = cmds; cmdp->name != NULLCHAR; cmdp++) {
  298.         if (strncmpi (argv[0], cmdp->name, strlen (argv[0])) == 0)
  299.             break;
  300.     }
  301.     if (cmdp->name == NULLCHAR) {
  302. #ifdef SCRIPTING
  303.         if (Curproc->gotolabel)
  304.             goto multichk;
  305. #endif
  306.         if (cmdp->argc_errmsg != NULLCHAR)
  307.             tprintf ("%s\n", cmdp->argc_errmsg);
  308.         goto errret;
  309.     } else {
  310. #ifdef SCRIPTING
  311.         /* if we are in a goto command, and this is NOT a label
  312.            command, skip it.... */
  313.         if (Curproc->gotolabel && strcmp ("label", cmdp->name))
  314.             goto multichk;
  315. #endif
  316.         if (argc < cmdp->argcmin) {
  317.             /* Insufficient arguments */
  318.             tprintf ("Usage: %s\n", (cmdp->argc_errmsg) ? cmdp->argc_errmsg : "Try a '?' parameter for help");
  319.             goto errret;
  320.         } else {
  321.             if (cmdp->stksize == 0) {
  322.                 i = (*cmdp->func) (argc, (char **) argv, p);
  323.                 if (i)
  324.                     return i;
  325.                 goto multichk;
  326.             } else {
  327.                 /* Make private copy of argv and args,
  328.                  * spawn off subprocess and return.
  329.                  */
  330.                 isconv = (!stricmp (cmdp->name, "conference")
  331.                       || !stricmp (cmdp->name, "rlogin")
  332.                       || !stricmp (cmdp->name, "quote")
  333.                       || !stricmp (cmdp->name, "tutor")
  334.                       || !stricmp (cmdp->name, "info")
  335.                       || !stricmp (cmdp->name, "news"));
  336.                 pargv = (char **) callocw ((unsigned) ((isconv) ? 3 : argc), sizeof (char *));
  337.  
  338.                 for (i = 0; i < argc; i++)
  339.                     pargv[i] = strdup (argv[i]);
  340.                 (void) newproc (cmdp->name, (unsigned) cmdp->stksize,
  341.                      (void (*)(int, void *, void *)) cmdp->func, (isconv) ? 3 : argc, pargv, p, 1);
  342.                 goto multichk;
  343.             }
  344.         }
  345.     }
  346.  
  347. multichk:
  348.     if (nextline != NULLCHAR) {
  349.         line = nextline;
  350.         goto loop;
  351.     }
  352.     redir_cleanup ();
  353.     return 0;
  354.  
  355.  
  356. errret:
  357.     if (nextline != NULLCHAR)
  358.         tprintf ("*** Didn't execute: %s\n", nextline);
  359.     redir_cleanup ();
  360.     return -1;
  361. }
  362.  
  363.  
  364. /* Call a subcommand based on the first token in an already-parsed line */
  365. int
  366. subcmd (tab, argc, argv, p)
  367. struct cmds tab[];
  368. int argc;
  369. char *argv[];
  370. void *p;
  371. {
  372. register struct cmds *cmdp;
  373. struct proc *pp;
  374. char **pargv;
  375. int found = 0;
  376. int i;
  377.  
  378.     /* Strip off first token and pass rest of line to subcommand */
  379.     if (argc < 2) {
  380.         if (argc < 1)
  381.             tputs ("SUBCMD - Don't know what to do?\n");
  382.         else
  383. #if 1
  384.             dohelper ("valid subcommands:\n", tab, NULLCHAR, NULLCHAR, NULLCHAR);
  385. #else
  386.             tprintf ("\"%s\" - takes at least one argument\n", argv[0]);
  387. #endif
  388.         return -1;
  389.     }
  390.     argc--;
  391.     argv++;        /*lint !e608 */
  392.     for (cmdp = tab; cmdp->name != NULLCHAR; cmdp++) {
  393.         if (strncmpi (argv[0], cmdp->name, strlen (argv[0])) == 0) {
  394.             found = 1;
  395.             break;
  396.         }
  397.     }
  398.     if (!found) {
  399.         dohelper ("valid subcommands:\n", tab, NULLCHAR, NULLCHAR, NULLCHAR);
  400.         return -1;
  401.     }
  402.     if (argc < cmdp->argcmin) {
  403.         if (cmdp->argc_errmsg != NULLCHAR)
  404.             tprintf ("Usage: %s\n", cmdp->argc_errmsg);
  405.         return -1;
  406.     }
  407.     if (cmdp->stksize == 0)
  408.         return (*cmdp->func) (argc, argv, p);
  409.     else {
  410.         /* Make private copy of argv and args */
  411.         pargv = (char **) callocw ((unsigned) argc, sizeof (char *));
  412.  
  413.         for (i = 0; i < argc; i++)
  414.             pargv[i] = strdup (argv[i]);
  415.         pp = newproc (cmdp->name, (unsigned) cmdp->stksize,
  416.              (void (*)(int, void *, void *)) cmdp->func, argc, pargv, p, 1);
  417.         pp->ptype = cmdparse_newproc_type;
  418.         return (0);
  419.     }
  420. }
  421.  
  422.  
  423. /* Subroutine for setting and displaying boolean flags */
  424. int
  425. setbool (var, label, argc, argv)
  426. int *var;
  427. char const *label;
  428. int argc;
  429. char *argv[];
  430. {
  431. struct boolcmd *bc;
  432.  
  433.     if (argc < 2) {
  434.         tprintf ("%s: %s\n", label, *var ? "on" : "off");
  435.         return 1;
  436.     }
  437.     for (bc = Boolcmds; bc->str != NULLCHAR; bc++) {
  438.         if (strcmpi (argv[1], bc->str) == 0) {
  439.             *var = bc->val;
  440.             return 0;
  441.         }
  442.     }
  443.     tputs ("Valid options:");
  444.     for (bc = Boolcmds; bc->str != NULLCHAR; bc++)
  445.         if (tprintf (" %s", bc->str) == EOF)
  446.             return 1;
  447.     tputc ('\n');
  448.     return 1;
  449. }
  450.  
  451.  
  452. /* Subroutine for setting and displaying bit values */
  453. int
  454. bit16cmd (int16 *bits, int16 mask, const char *label, int argc, char *argv[])
  455. {
  456. int doing = (*bits & mask);
  457. int result = setbool (&doing, label, argc, argv);
  458.  
  459.     if (!result) {
  460.         if (doing)
  461.             *bits |= mask;
  462.         else
  463.             *bits &= ~mask;
  464.     }
  465.     return result;
  466. }
  467.  
  468.  
  469. /* Subroutine for setting and displaying long variables */
  470. int
  471. setlong (var, label, argc, argv)
  472. long *var;
  473. char const *label;
  474. int argc;
  475. char *argv[];
  476. {
  477.     if (argc < 2) {
  478.         tprintf ("%s: %ld (0x%08lx)\n", label, *var, *var);
  479.         return 1;
  480.     } else {
  481.         if (!strncmp (argv[1], "0x", 2))
  482.             *var = htol (argv[1]);
  483.         else if (argv[1][0] == '%')
  484.             *var = btol (argv[1]);
  485.         else
  486.             *var = atol (argv[1]);
  487.         return 0;
  488.     }
  489.  
  490. }
  491.  
  492.  
  493. /* Subroutine for setting and displaying short variables */
  494. int
  495. setshort (var, label, argc, argv)
  496. unsigned short *var;
  497. char const *label;
  498. int argc;
  499. char *argv[];
  500. {
  501.     if (argc < 2) {
  502.         tprintf ("%s: %u (0x%04x)\n", label, *var, *var);
  503.         return 1;
  504.     } else {
  505.         if (!strncmp (argv[1], "0x", 2))
  506.             *var = (int16) htoi (argv[1]);
  507.         else if (argv[1][0] == '%')
  508.             *var = (unsigned short) btol (argv[1]);
  509.         else
  510.             *var = (int16) atoi (argv[1]);
  511.         return 0;
  512.     }
  513. }
  514.  
  515.  
  516. /* Subroutine for setting and displaying integer variables */
  517. int
  518. setint (var, label, argc, argv)
  519. int *var;
  520. char const *label;
  521. int argc;
  522. char *argv[];
  523. {
  524.     if (argc < 2) {
  525.         tprintf ("%s: %i (0x%04x)\n", label, *var, *var);
  526.         return 1;
  527.     } else {
  528.         if (!strncmp (argv[1], "0x", 2))
  529.             *var = htoi (argv[1]);
  530.         else if (argv[1][0] == '%')
  531.             *var = (int) btol (argv[1]);
  532.         else
  533.             *var = atoi (argv[1]);
  534.         return 0;
  535.     }
  536.  
  537. }
  538.  
  539.  
  540. /* Subroutine for setting and displaying unsigned integer variables */
  541. int
  542. setuns (var, label, argc, argv)
  543. unsigned *var;
  544. char const *label;
  545. int argc;
  546. char *argv[];
  547. {
  548.     if (argc < 2) {
  549.         tprintf ("%s: %u (0x%04x)\n", label, *var, *var);
  550.         return 1;
  551.     } else {
  552.         if (!strncmp (argv[1], "0x", 2))
  553.             *var = (int16) htoi (argv[1]);
  554.         else if (argv[1][0] == '%')
  555.             *var = (unsigned) btol (argv[1]);
  556.         else
  557.             *var = (int16) atoi (argv[1]);
  558.         return 0;
  559.     }
  560. }
  561.  
  562.  
  563. /* Subroutine for setting and displaying int variables (with range check) */
  564. int
  565. setintrc (int16 *var, char const *label, int argc, char *argv[], int minval, int16 maxval)
  566. {
  567. int tmp;
  568.  
  569.     if (argc < 2)
  570.         tprintf ("%s: %u (0x%04x)\n", label, *var, *var);
  571.     else {
  572.         if (!strncmp (argv[1], "0x", 2))
  573.             tmp = htoi (argv[1]);
  574.         else if (argv[1][0] == '%')
  575.             tmp = (int) btol (argv[1]);
  576.         else
  577.             tmp = atoi (argv[1]);
  578.         if (isalpha (*argv[1]) || tmp < minval || tmp > maxval) {
  579.             tprintf ("%s must be %i..%i\n", label, minval, maxval);
  580.             return 1;
  581.         }
  582.         *var = (int16) tmp;
  583.     }
  584.     return 0;
  585. }
  586.